<?php

namespace App\Console\Commands;

use App\Ethereum;
use App\Models\Sync;
use App\Models\Transaction;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

declare(ticks=1);

class SyncEthereumTransaction extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'sync:transactions {address} {--daemonize} {--loop}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Sync transactions of eth address';

    protected $eth;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct(Ethereum $eth)
    {
        parent::__construct();

        $this->eth = $eth;
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {       
        $address = $this->argument('address');

        if ($this->option('daemonize')) {
            daemonize();
        }

        if (strpos($address, '0x') === false || strlen($address) != 42) {
            $this->error('Incorrect format of address');
        } else {

            $address = strtolower($address);

            if ($this->option('daemonize') || $this->option('loop')) {
                $pid = posix_getpid();
                Storage::put('pids/' . $address . '-' . $pid . '.pid', $pid);
                install_sigterm_signal_handler();
            }

            $order = 'desc';

            $offset = 100;
            $page = 1;

            $this->info(sprintf('page=%d', $page));
            $this->info(sprintf('offset=%d', $offset));

            $this->info('Start...');

            $flag = true;

            while ($flag) {

                try {

                    $current_total_count = Transaction::where('to', '=', $address)->orWhere('from', '=', $address)->count();

                    $sync = new Sync;

                    $sync->type = 'transaction';

                    $sync->save();

                    if ($current_total_count) {
                        $new_data = json_decode($this->eth->getTransactionsByAddress($address, 2, $current_total_count, $order), true);

                        if ($new_data['status'] == 1 && $new_data['message'] == 'OK' && count($new_data['result']) > 0) {
                            $page = $current_total_count / $offset + 1;    
                        } else {
                            if ($this->option('daemonize') || $this->option('loop')) {
                                sleep(900);
                                continue;
                            } else {
                                $this->info('Everything done.');
                                return;
                            }
                        }
                        
                    }

                    $this->info(sprintf('Get page %d data...', $page));

                    if ($current_total_count > 0 && $current_total_count % $offset == 0) {
                        $data = $new_data;
                    } else {
                        $data = $this->eth->getTransactionsByAddress($address, $page, $offset, $order);
                        $data = json_decode($data, true);  
                    }                              

                    if ($data['status'] == 1 && $data['message'] == 'OK' && count($data['result']) > 0) {

                        $this->info('Insert data to database...');
                        $this->insertData($data['result']);

                    } 

                } catch (\GuzzleHttp\Exception\ConnectException $e) {
                    //
                }              
            }
            
        }
    }

    private function insertData($data)
    {
        foreach ($data as $value) {
            DB::table('transactions')->where('hash', $value['hash'])->first() || DB::table('transactions')->insert($value); 
        }
        
    }
}
